

<template>
  <div style="width:100%">
    <el-select v-if="mode=='select'" ref="select" v-model="defaultValue" :value-key="props.label" :size="size" :clearable="clearable" :multiple="multiple" :collapse-tags="collapseTags" :filterable="filterable" :placeholder="placeholder"
      :disabled="disabled" :filter-method="filterMethod" @remove-tag="removeTag" @visible-change="visibleChange" @clear="clear" style="width: 100%;">
      <template slot="empty">
        <div class="table-select__table" v-loading="loading" :style="{width: '100%'}">
          <div class="table-tree" v-if="tree">
            <el-scrollbar style="height:100%" wrap-style="overflow-x:hidden;">
              <el-tree :data="treeData" :props="treeProps" @node-click="handleNodeClick"></el-tree>
            </el-scrollbar>
          </div>
          <div class="table-select-right">
            <div class="table-select__header">
              <el-form :model="formData" label-position="left" class="query-form" inline size="small">
                <el-form-item :label="item.label" v-for="item in query" :key="item.prop">
                  <el-input :placeholder="'请输入' + item.label" v-model="formData[item.prop]" class="w-[280px]" clearable />
                </el-form-item>
                <slot name="header" :formData="formData" :submit="formSubmit"></slot>
                <el-form-item>
                  <el-button type="primary" @click="formSubmit">查询</el-button>
                  <slot name="btns"></slot>
                </el-form-item>
              </el-form>
            </div>
            <el-table style="width:100%" ref="table" :data="tableData" :height="tableHeight" :highlight-current-row="!multiple" @row-click="click" @select="select" @select-all="selectAll" size="small">
              <el-table-column v-if="multiple" type="selection" width="55" align="center"></el-table-column>
              <el-table-column v-else type="index" width="55" label='序号' align="center">
                <template slot-scope="scope">
                  <span>{{scope.$index+(currentPage - 1) * pageSize + 1}}</span>
                </template>
              </el-table-column>
              <!-- 循环 columns -->
              <el-table-column v-if="columns.length!=0" v-for="(item, index) in columns" :key="item.prop" :prop="item.prop" :label="item.label" :align="item.align || 'left'" :min-width="item.min_width ? item.min_width : 100"
                :show-overflow-tooltip="!item.overflow?true:item.overflow">
                <template slot-scope="scope">
                  <!-- 特殊格式可用插槽处理  -->
                  <slot :name="item.prop" v-bind="scope">{{ scope.row[item.prop] }}</slot>
                </template>
              </el-table-column>
              <!--不用columns 可定义el-table-column  -->
              <slot></slot>
            </el-table>
            <div class="table-select__page" v-if="total>0&&pagination">
              <el-pagination small background layout="prev, pager, next,total" :total="total" :page-size.sync="pageSize" :current-page.sync="currentPage" @current-change="reload"></el-pagination>
            </div>
          </div>
        </div>
      </template>
    </el-select>

    <div v-else>
      <el-button :disabled="disabled" type="primary" @click="openDialog" v-if="btnText">{{btnText}}</el-button>
      <el-input readonly v-else :placeholder="placeholder" v-model="defaultValueInput">
        <el-button :disabled="disabled" slot="append" icon="el-icon-search" @click="openDialog"></el-button>
        <template #header="{formData,formSubmit}">
          <slot name="headers" :formData="formData" :submit="formSubmit"></slot>
        </template>
      </el-input>
      <el-dialog append-to-body :title="placeholder" :visible.sync="dialogVisible" :width="tableWidth" :before-close="close">
        <div class="table-select__table" v-loading="loading">
          <div class="table-tree" v-if="tree">
            <el-scrollbar style="height:100%" wrap-style="overflow-x:hidden;">
              <el-tree :data="treeData" :props="treeProps" @node-click="handleNodeClick"></el-tree>
            </el-scrollbar>
          </div>
          <div class="table-select-right">
            <div class="table-select__header">
              <el-form :model="formData" label-position="left" class="query-form" inline size="small">
                <el-form-item :label="item.label" v-for="item in query" :key="item.prop">
                  <el-input :placeholder="'请输入' + item.label" v-model="formData[item.prop]" class="w-[280px]" clearable />
                </el-form-item>
                <slot name="header" :formData="formData" :submit="formSubmit"></slot>
                <el-form-item>
                  <el-button type="primary" @click="formSubmit">查询</el-button>
                  <slot name="btns"></slot>
                </el-form-item>
              </el-form>
            </div>
            <el-table style="width: 100%;" ref="table" :data="tableData" :height="tableHeight" :highlight-current-row="!multiple" @row-click="click" @select="select" @select-all="selectAll" size="small">
              <el-table-column v-if="multiple" type="selection" width="55" align="center"></el-table-column>
              <el-table-column v-else type="index" width="55" label='序号' align="center">
                <template slot-scope="scope">
                  <span>{{scope.$index+(currentPage - 1) * pageSize + 1}}</span>
                </template>
              </el-table-column>
              <!-- 循环 columns -->
              <el-table-column v-if="columns.length!=0" v-for="(item, index) in columns" :key="item.prop" :prop="item.prop" :label="item.label" :align="item.align || 'left'" :min-width="item.min_width ? item.min_width : 100"
                :show-overflow-tooltip="!item.overflow?true:item.overflow">
                <template slot-scope="scope">
                  <!-- 特殊格式可用插槽处理  -->
                  <slot :name="item.prop" v-bind="scope">{{ scope.row[item.prop] }}</slot>
                </template>
              </el-table-column>
              <!--不用columns 可定义el-table-column  -->
              <slot></slot>
            </el-table>
            <div class="table-select__page" v-if="total>0&&pagination">
              <el-pagination small background layout="prev, pager, next,total" :total="total" :page-size.sync="pageSize" :current-page.sync="currentPage" @current-change="reload"></el-pagination>
            </div>
          </div>
        </div>
        <span slot="footer" class="dialog-footer">
          <el-button @click="close">取 消</el-button>
          <el-button type="primary" @click="sureSelect">确 定</el-button>
        </span>
      </el-dialog>
    </div>
  </div>
</template>

<script>

export default {
  props: {
    value: [Object, Array], // v-modle的值
    btnText: String, //按钮文字 
    mode: { type: String, default: "select" }, //选择的类型是 select下拉 dialog是弹框
    fetchFun: [Function, Array], //请求接口 或者数据
    pagination: { type: Boolean, default: true }, //是否使用分页
    params: { type: Object, default: () => { } }, //查询条件 查询时需要附带的其他额外参数
    columns: { type: Array, default: () => [] },  //表格的columns
    placeholder: { type: String, default: "请选择" }, //select 的placeholder 值
    size: { type: String, default: "small" }, //尺寸
    clearable: { type: Boolean, default: false },  //是否可以清空选项
    multiple: { type: Boolean, default: false },  //是否多选
    filterable: { type: Boolean, default: false }, //是否可搜索
    collapseTags: { type: Boolean, default: false },//多选时是否将选中值按文字的形式展示
    disabled: { type: Boolean, default: false }, //是否禁用
    tableWidth: { type: String, default: '700px' }, //表格宽度
    tableHeight: { type: Number, default: 300 }, //表格高度
    query: { type: Array, default: () => [] }, //表头查询字段 
    //表头自定义 参考如下
    // <template #header="{formData}">
    //   <el-form-item label="自定义搜索">
    //     <el-input clearable v-model="formData.nickname" placeholder="名称"></el-input>
    //   </el-form-item>
    // </template>

    //映射label显示字段 value值字段  keyword可搜索的字段
    props: {
      type: Object,
      default: () => {
        return {
          label: 'label',
          value: 'id',
          keyword: 'label'
        }
      }
    },
    // 自定义接口请求的数据结构
    parseData: {
      type: Function,
      default: (res) => {
        return {
          data: res.data,//行数据字段结构
          total: res.total ? res.total : 0,//总数字段结构
        }
      }
    },
    fetchTreeFun: { type: Function }, //树形数据接口
    tree: { type: Boolean, default: false },  //是否显示树形结构
    parseTreeData: {
      type: Function,
      default: (res) => {
        return {
          data: res.data,//行数据字段结构
        }
      }
    },
    //参考树形  props
    treeProps: {
      type: Object,
      default: () => {
        return {
          children: 'children',
          label: 'label'
        }
      }
    },
    // 点击树形的需要的向 table 传递的查询参数 与tree的对应key value 为树的对应key  label为table 的查询key
    treeParamKeys: {
      type: Object,
      default: () => {
        return {
          value: 'id',
          label: 'pid'
        }
      }
    }

  },
  data() {
    return {
      loading: false,
      keyword: null,
      defaultValue: [],
      tableData: [],
      pageSize: 10,
      total: 0,
      currentPage: 1,
      defaultProps: {
        page: 'pageNo',				//规定当前分页字段
        pageSize: 'pageSize',			//规定一页条数字段
      },
      formData: {},
      treeData: [],
      defaultValueInput: '',
      dialogVisible: false
    }
  },
  computed: {

  },
  watch: {
    value: {
      handler() {
        if (this.multiple) {
          if (!this.value) {
            this.defaultValue = [];
          } else {
            this.defaultValue = this.value;
          }
        } else {
          if (!this.value) {
            this.defaultValue = {};
          } else {
            this.defaultValue = this.value;
          }
        }
        this.autoCurrentLabel();
        if(this.mode=='dialog'){
            this.defaultValueInput = this.mapArry()
        }

      },
      deep: true
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.defaultProps = Object.assign(this.defaultProps, this.props);
      if (this.multiple) {
        if (!this.value) {
          this.defaultValue = [];
        } else {
          this.defaultValue = this.value;
        }
      } else {
        if (!this.value) {
          this.defaultValue = {};
        } else {
          this.defaultValue = this.value;
        }
      }
      this.autoCurrentLabel()
    })
  },
  methods: {
    mapArry() {
      if (this.defaultValue) {
        if (Array.isArray(this.defaultValue)) {
          return this.defaultValue.map(obj => obj[this.props.label]).join(',');
        } else {
          return this.defaultValue[this.props.label]
        }
      }
    },
    openDialog() {
      this.open();
    },
    open() {
      this.dialogVisible = true
      this.currentPage = 1
      this.keyword = null
      this.formData = {}
      if (this.tree) {
        this.getTreeData()
      }
      this.getData()
    },
    close() {
      this.dialogVisible = false
      this.autoCurrentLabel()
    },
    handleNodeClick(node) {
      this.formData[this.treeParamKeys.label] = node[this.treeParamKeys.value]
      this.getData()
    },
    handleNodeClick(node) {
      this.formData[this.treeParamKeys.label] = node[this.treeParamKeys.value]
      this.getData()
    },
    //表格显示隐藏回调
    visibleChange(visible) {
      if (visible) {
        this.currentPage = 1
        this.keyword = null
        this.formData = {}
        if (this.tree) {
          this.getTreeData()
        }
        this.getData()
      } else {
        this.autoCurrentLabel()
      }
    },
    async getTreeData() {
      if (typeof (this.fetchTreeFun) == 'function') {
        var res = await this.fetchTreeFun({});
        var parseData = this.parseTreeData(res)
        this.treeData = parseData.data;
      }
    },
    //获取表格数据
    async getData() {
      this.loading = true;
      if (typeof (this.fetchFun) == 'function') {
        var reqData = {
        }
        this.formData[this.props.keyword] = this.keyword;
        if (this.pagination) {
          reqData = {
            [this.defaultProps.page]: this.currentPage,
            [this.defaultProps.pageSize]: this.pageSize,
          }
        }
        Object.assign(reqData, this.params, this.formData)
        var res = await this.fetchFun(reqData);
        var parseData = this.parseData(res)
        this.tableData = parseData.data;
        this.total = parseData.total;
      } else {
        this.tableData = this.fetchFun;
      }
      this.loading = false;
      //表格默认赋值
      this.$nextTick(() => {
        if (!this.defaultValue) return
        if (this.multiple) {
          this.defaultValue.forEach(row => {
            var setrow = this.tableData.filter(item => item[this.defaultProps.value] === row[this.defaultProps.value])
            if (setrow.length > 0) {
              this.$refs.table.toggleRowSelection(setrow[0], true);
            }
          })
        } else {
          var setrow = this.tableData.filter(item => item[this.defaultProps.value] === this.defaultValue[this.defaultProps.value])
          this.$refs.table.setCurrentRow(setrow[0]);
        }
      })
    },
    //插糟表单提交
    formSubmit() {
      this.currentPage = 1
      this.keyword = null
      this.getData()
    },
    //分页刷新表格
    reload() {
      this.getData()
    },
    //自动模拟options赋值
    autoCurrentLabel() {
      if (!this.defaultValue) return
      if (this.mode == 'dialog') return
      this.$nextTick(() => {
        if (this.multiple) {
          this.$refs.select.selected.forEach(item => {
            item.currentLabel = item.value[this.defaultProps.label]
          })
        } else {
          this.$refs.select.selectedLabel = this.defaultValue[this.defaultProps.label]
        }
      })
    },
    //表格勾选事件
    select(rows, row) {
      var isSelect = rows.length && rows.indexOf(row) !== -1
      if (isSelect) {
        this.defaultValue.push(row)
      } else {
        this.defaultValue.splice(this.defaultValue.findIndex(item => item[this.defaultProps.value] == row[this.defaultProps.value]), 1)
      }
      this.autoCurrentLabel()
      this.$emit('input', this.defaultValue);
      this.$emit('change', this.defaultValue);
    },
    //表格全选事件
    selectAll(rows) {
      var isAllSelect = rows.length > 0
      if (isAllSelect) {
        rows.forEach(row => {
          var isHas = this.defaultValue.find(item => item[this.defaultProps.value] == row[this.defaultProps.value])
          if (!isHas) {
            this.defaultValue.push(row)
          }
        })
      } else {
        this.tableData.forEach(row => {
          var isHas = this.defaultValue.find(item => item[this.defaultProps.value] == row[this.defaultProps.value])
          if (isHas) {
            this.defaultValue.splice(this.defaultValue.findIndex(item => item[this.defaultProps.value] == row[this.defaultProps.value]), 1)
          }
        })
      }
      this.autoCurrentLabel()
      this.$emit('input', this.defaultValue);
      this.$emit('change', this.defaultValue);
    },
    click(row) {
      if (this.multiple) {
        //处理多选点击行
      } else {
        this.defaultValue = row
        if(this.mode=='select'){
          this.$refs.select.blur()
        }
        this.autoCurrentLabel()
        this.$emit('input', this.defaultValue);
        this.$emit('change', this.defaultValue);
      }
    },
    //tags删除后回调
    removeTag(tag) {
      var row = this.findRowByKey(tag[this.defaultProps.value])
      this.$refs.table.toggleRowSelection(row, false);
      this.autoCurrentLabel()
      this.$emit('input', this.defaultValue);
    },
    //清空后的回调
    clear() {
      this.autoCurrentLabel()
      this.$emit('input', this.defaultValue);
    },
    // 关键值查询表格数据行
    findRowByKey(value) {
      return this.tableData.find(item => item[this.defaultProps.value] === value)
    },
    filterMethod(keyword) {
      if (!keyword) {
        this.keyword = null;
        return false;
      }
      this.keyword = keyword;
      this.getData()
    },
    // 触发select隐藏
    blur() {
      this.$refs.select.blur();
    },
    // 触发select显示
    focus() {
      this.$refs.select.focus();
    },
    sureSelect() {
      this.$emit('input', this.defaultValue);
      this.$emit('change', this.defaultValue);
      this.dialogVisible = false;
      
    },
  }
}
</script>

<style scoped>
.table-select__table {
  padding: 12px;
  display: flex;
  justify-content: flex-start;
}
.table-tree {
  margin-right: 15px;
  width: 200px;
  border-right: 1px solid #eaeaea;
}
.table-select__page {
  padding-top: 12px;
}
.table-select-right {
  flex: 1;
}
</style>
